﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using hamster.WorldObjects;

namespace hamster
{
    class Plant : WorldObject
    {
        public const int FRUIT_BEARING_HEIGHT = 6;
        public const float LEAF_HEIGHT_VARIANCE = 0.1f;
        public const float LEAF_WIDTH_VARIANCE = .05f;
        public const float LEAF_Z_VARIANCE = 0.8f;
        public const float AVERAGE_FRUIT_SPAWN_TIME = 40;
        public const float GROW_LEVEL_COUNTDOWN = 30;
        public const float NOURISH_DIST = 2f;
        public const float NOURISH_VAL = 10f;
        public const float SHAKE_AMOUNT = .2f;
        public const float PLANT_GROWTH = .5f;
        private List<Leaf> leaves_;
        public float plantHeight_;
        public float fruitSpawnCountdown_;
        public List<Leaf> leavesToRemove_;

        public Plant(Vector2 position, float rotation, ObjectPlacer parent) : base(position, rotation, parent) {
            leaves_ = new List<Leaf>();
            leavesToRemove_ = new List<Leaf>();
            plantHeight_ = .5f + Game1.RandomFloat * (FRUIT_BEARING_HEIGHT - 1);
            updateLeafCount();
            fruitSpawnCountdown_ = 0;

            foreach (Leaf leaf in leaves_)
                leaf.initialGrowth_ = 1;
        }

        public void RemoveLeaf(Leaf item)
        {
            leavesToRemove_.Add(item);
        }

        public override bool Update(float dt, Player player)
        {
            if (leaves_.Count <= 0)
            {
                return true;
            }

            plantHeight_ += dt * (float) Game1.random.NextDouble() * PLANT_GROWTH;
            if (Vector2.Distance(new Vector2(player.position.X, player.position.Y), position_) <= NOURISH_DIST && player.nourish_ && plantHeight_ < FRUIT_BEARING_HEIGHT)
            {
                plantHeight_ += NOURISH_VAL * dt;
                player.brightness -= Player.ENERGY_DRAIN * dt;
                localTransformations_ = Matrix.CreateTranslation(Game1.RandomNegPos() * SHAKE_AMOUNT, Game1.RandomNegPos() * SHAKE_AMOUNT / 2, 0);
            }
            plantHeight_ = MathHelper.Clamp(plantHeight_, 0, FRUIT_BEARING_HEIGHT);

            if (plantHeight_ == FRUIT_BEARING_HEIGHT)
            {
                if (fruitSpawnCountdown_ <= 0 && leaves_.Count >= 1)
                {
                    SpawnFruit();
                }
                else
                {
                    fruitSpawnCountdown_ -= dt;
                }
            }

            foreach (Leaf leaf in leaves_)
            {
                leaf.Update(dt, player, localTransformations_, true);
            }
            foreach (Leaf leaf in leavesToRemove_){
                leaves_.Remove(leaf);
            }

            // Nourishment meter decreases (at a rate proportional to height?)
            updateLeafCount();

            // Don't want to remove plant
            return false;
        }

        private void updateLeafCount()
        {
            if (plantHeight_ == FRUIT_BEARING_HEIGHT)
                return;

            for (int i = leaves_.Count; i < plantHeight_ * 2; i++)
            {
                int coeff = (i % 4 == 0) ? -1 : 1;
                Vector2 relLeafPos = new Vector2();
                relLeafPos.X = Leaf.LEAF_SIZE * 0.25f + Game1.RandomNegPos() * Leaf.LEAF_SIZE * LEAF_WIDTH_VARIANCE * 0.1f;
                relLeafPos.X *= coeff;
                relLeafPos.Y = (-i / 3) * Leaf.LEAF_SIZE *1.5f + Leaf.LEAF_SIZE * (float)Game1.random.NextDouble();
                relLeafPos = Vector2.Transform(relLeafPos, Matrix.CreateRotationZ(rotation_));
                //Matrix transformMatrix = Matrix.CreateRotationZ(rotation_) * Matrix.CreateTranslation(position_.X, leafY, 0);
                Vector2 leafpos = Vector2.Add(position_, relLeafPos);
                leaves_.Add(new Leaf(leafpos, rotation_, parent_, this));
            }
        }

        public override void Draw(GraphicsDevice device)
        {
            // Scale it in when player draws near?
            foreach (Leaf leaf in leaves_)
            {
                leaf.Draw(device);
            }
        }

        internal void SpawnFruit()
        {
            // Choose a random leaf and spawn fruit
            int i = Game1.random.Next(4);
            Leaf randleaf = leaves_[leaves_.Count - 1 - i];
            if (!randleaf.isGrown())
                return;
            fruitSpawnCountdown_ = AVERAGE_FRUIT_SPAWN_TIME + Game1.RandomNegPos() * AVERAGE_FRUIT_SPAWN_TIME / 2;
            Fruit fruit = randleaf.SpawnFruit();
            parent_.activeFruit_.Add(fruit);
        }
    }
}
